package com.skynet.supervision.services.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.skynet.supervision.aop.uac.JwtUtil;
import com.skynet.supervision.aop.uac.UACUserContext;
import com.skynet.supervision.aop.uac.beans.UACTokenInfo;
import com.skynet.supervision.aop.uac.beans.UACUserInfo;
import com.skynet.supervision.beans.request.user.AddUserRequest;
import com.skynet.supervision.beans.request.user.EditUserRequest;
import com.skynet.supervision.beans.request.user.GetDetailRequest;
import com.skynet.supervision.beans.request.user.ListByPageRequest;
import com.skynet.supervision.beans.request.users.RevisePassRequest;
import com.skynet.supervision.beans.request.users.UserAddRequest;
import com.skynet.supervision.beans.request.users.UserLoginRequest;
import com.skynet.supervision.beans.response.UserLoginResponse;
import com.skynet.supervision.beans.response.user.DeptUserItemResponse;
import com.skynet.supervision.beans.response.user.GetUserDetailsResponse;
import com.skynet.supervision.beans.response.user.UserItemResponse;
import com.skynet.supervision.beans.vo.dept.DeptItemVo;
import com.skynet.supervision.common.ErrCode;
import com.skynet.supervision.common.Result;
import com.skynet.supervision.dao.*;
import com.skynet.supervision.entities.UserAccount;
import com.skynet.supervision.entities.UserInfo;
import com.skynet.supervision.enums.RoleMenu;
import com.skynet.supervision.enums.UserAccountStatus;
import com.skynet.supervision.services.UserService;
import com.skynet.supervision.utils.AccountUtils;
import com.skynet.supervision.utils.TimeUtils;
import com.skynet.supervision.utils.TokenCacheUtils;
import com.skynet.supervision.utils.UuidUtils;
import dm.jdbc.util.StringUtil;
import lombok.SneakyThrows;
import lombok.val;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.Instant;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    private final JwtUtil jwtUtil;
    private final UserAccountMapper userAccountMapper;
    private final UserInfosMapper userInfosMapper;
    private final SysDeptMapper sysDeptMapper;
    private final SysDeptPostMapper sysDeptPostMapper;

    public UserServiceImpl(JwtUtil jwtUtil, UserAccountMapper userAccountMapper, UserInfosMapper userInfosMapper,  SysDeptMapper sysDeptMapper, SysDeptPostMapper sysDeptPostMapper) {
        this.jwtUtil = jwtUtil;
        this.userAccountMapper = userAccountMapper;
        this.userInfosMapper = userInfosMapper;
        this.sysDeptMapper = sysDeptMapper;
        this.sysDeptPostMapper = sysDeptPostMapper;
    }

    @Override
    @SneakyThrows
    public UserLoginResponse login(UserLoginRequest request) {
        UserAccount account = Optional
                .ofNullable(userAccountMapper.getOneByAccount(request.getAccount()))
                .orElseThrow(() -> Result.failure(ErrCode.USER_NOT_FOUND).wrap());

        UserInfo userInfo = this.userInfosMapper.queryByUserId(account.getId());

        AccountUtils.checkAccountStatusOrThrow(account);

        AccountUtils.checkPassOrThrow(account.getPassword(), request.getPassword(), account.getId());

        List<DeptItemVo> deptItem = userInfosMapper.getDeptIdByUid(account.getId());
        String deptName = "";
        if(deptItem.size()>0){
            deptName = deptItem.get(0).getDeptName();
        }
        return UserLoginResponse
                .builder()
                .tokenInfo(buildToken(account.getSysNodeCode(), account.getId()))
                .userInfo(UACUserInfo
                        .builder()
                        .userId(account.getId())
                        .account(account.getAccount())
                        .status(account.getStatus())
                        .email(userInfo.getEmail())
                        .rongCloudToken(userInfo.getRongCloudToken())
                        .sex(account.getSex())
                        .name(account.getUserName())
                        .avatar(account.getAvatar())
                        .titles(userInfo.getTitles())
                        .deptName(deptName)
                        .lastLoginTime(account.getLastLoginAt())
                        .ifDriver(account.getRole()!=null && account.getRole().equals(RoleMenu.SIJI.getDesc()))
                        .build())
                .build();
    }

    @Override
    @SneakyThrows
    public UACUserInfo checkToken() {
        val user = UACUserContext.currentUserOrAnonymous();
        if(user.isAnonymous()){
            throw Result.failure(ErrCode.TOKEN_INVALID.getCode(), "用户未登录或登录已失效").wrap();
        }
        return user;
    }

    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public void addUser(UserAddRequest request) {
        val exist = userAccountMapper.getOneByAccount(request.getAccount());
        if (exist != null) {
            throw Result.failure(ErrCode.USER_NOT_DUPLICATE).wrap();
        }
        UserAccount account = new UserAccount();
        account.setAccount(request.getAccount());
        account.setUserName(request.getName());
        account.setStatus(UserAccountStatus.NORMAL.getStatus());
        account.setLastLoginAt(Instant.now().getEpochSecond());
        account.setPassword(request.getPassword());
        account.setAvatar("头像地址");
        account.setSex(Optional.ofNullable(request.getSex()).orElse("0"));
        userAccountMapper.insert(account);
        userAccountMapper.initPassword(account.getId(), AccountUtils.passwordEncrypt(request.getPassword(), account.getId()));
    }

//    @Override
//    public AppUpdateHeadImgResponse updateHeadImg(MultipartFile file) {
//        String userId = UACUserContext.currentUserOrAnonymous().getUserId();
//        UserAccount user = userAccountMapper.getOneById(userId);
//        AppUpdateHeadImgResponse response = new AppUpdateHeadImgResponse();
//        if(file!=null){
//            String imgUrl = this.fileService.addImg(file);
//            user.setAvatar(imgUrl);
//            response.setImg(imgUrl);
//        }
//        userAccountMapper.updateById(user);
//        return response;
//    }

    @Override
    public void revisePass(RevisePassRequest request) {
        UserAccount userAccount = userAccountMapper.selectById(request.getUserId());
        AccountUtils.checkPassOrThrow(userAccount.getPassword(), request.getOldPassWord(), userAccount.getId());

        String pass = AccountUtils.passwordEncrypt(request.getPassWord(), userAccount.getId());
        userAccount.setPassword(pass);
        userAccountMapper.updateById(userAccount);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(AddUserRequest request) {
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(request,userInfo);
        userInfo.setId(UuidUtils.randomUUID());
        userInfo.setCreateTime(TimeUtils.currentTime());
        userInfo.setUserId(UuidUtils.randomUUID());
        UserAddRequest userAddRequest =new UserAddRequest();
        userAddRequest.setAccount(request.getIdNumber());
        userAddRequest.setPassword(request.getIdNumber());
        userAddRequest.setName(request.getName());
        userAddRequest.setSex("1");
        this.addUser(userAddRequest);
        UserAccount account = this.userAccountMapper.getOneByAccount(request.getIdNumber());
        if(!StringUtil.isEmpty(request.getAvatar())){
            account.setAvatar(request.getAvatar());
            this.userAccountMapper.updateById(account);
        }

        userInfo.setUserId(account.getId());
        this.userInfosMapper.insert(userInfo);
    }

    @Override
    public GetUserDetailsResponse getuser(GetDetailRequest request) {
        GetUserDetailsResponse response = new GetUserDetailsResponse();
        UserInfo userInfo = this.userInfosMapper.selectOne(new QueryWrapper<UserInfo>().
                eq("user_id",request.getId()));
        UserAccount userAccount = this.userAccountMapper.getOneById(userInfo.getUserId());
        BeanUtils.copyProperties(userInfo,response);
        if(!StringUtils.isEmpty(userAccount.getAvatar())){
            response.setAvatar(userAccount.getAvatar());
        }
        return response;
    }

    @Override
    public Page<GetUserDetailsResponse> listByPage(ListByPageRequest request) {
        String userid = UACUserContext.currentUserOrAnonymous().getUserId();
        Page<UserInfo> page = new Page<>(request.getPage(),request.getPageSize());
        Page<GetUserDetailsResponse> response = new Page<GetUserDetailsResponse>();

        QueryWrapper<UserInfo> querywrapper = new QueryWrapper<UserInfo>();
        if(!StringUtil.isEmpty(request.getKey())){
            querywrapper.or(wrapper->wrapper.like("supervision_no",request.getKey()));
            querywrapper.or(wrapper->wrapper.like("id_number",request.getKey()));
            querywrapper.or(wrapper->wrapper.like("military_id_number",request.getKey()));
            querywrapper.and(wrapper->wrapper.like("name",request.getKey()));
        }
//        if(!StringUtil.isEmpty(request.getName())){
//            querywrapper.and(wrapper->wrapper.like("name",request.getName()));
//        }
        Page<UserInfo> userInfoPage = this.userInfosMapper.selectPage(page, querywrapper);
        BeanUtils.copyProperties(userInfoPage,response);
        List<GetUserDetailsResponse> collect = userInfoPage.getRecords().stream()
                .map(res -> {
                    GetUserDetailsResponse item = new GetUserDetailsResponse();
                    UserAccount userAccount = this.userAccountMapper.selectById(res.getUserId());
                    BeanUtils.copyProperties(res, item);
                    if(!StringUtil.isEmpty(userAccount.getPhone())){
                        item.setPhone(userAccount.getPhone());
                    }
                    List<DeptItemVo> deptItemVos = this.userInfosMapper.getDeptIdByUid(res.getUserId());
                    if(deptItemVos.size()>0){
                        if(!StringUtil.isEmpty(deptItemVos.get(0).getDeptName())){
                            item.setDeptName(deptItemVos.get(0).getDeptName());
                        }
                    }
                    if(!StringUtils.isEmpty(userAccount.getAvatar())){
                        item.setAvatar(userAccount.getAvatar());
                    }
                    return item;
                })
                .collect(Collectors.toList());
        response.setRecords(collect);
        return response;
    }

    @Override
    public List<DeptUserItemResponse> deptUserList() {
        return null;
    }

    @Override
    public String uploadHeaderImg(MultipartFile file) {
        return null;
    }
//
//    @Override
//    public List<DeptItemResponse> deptList() {
//        List<DeptItemResponse> responses = this.sysDeptMapper.selectList(new QueryWrapper<>())
//                .stream()
//                .map(res -> {
//                    DeptItemResponse item = new DeptItemResponse();
//                    item.setDeptName(res.getName());
//                    item.setId(res.getId());
//                    return item;
//                }).collect(Collectors.toList());
//        return responses;
//    }
//
//    @Override
//    public List<DeptPostItemResponse> deptPostList() {
//        List<DeptPostItemResponse> responses = this.sysDeptPostMapper.selectList(new QueryWrapper<>())
//                .stream()
//                .map(res -> {
//                    DeptPostItemResponse item = new DeptPostItemResponse();
//                    item.setDeptPostName(res.getName());
//                    item.setId(res.getId());
//                    return item;
//                }).collect(Collectors.toList());
//        return responses;
//    }
//
//    @Override
//    public List<UserItemResponse> listByDeptId(UserByDeptRequest request) {
//        List<UserItemResponse> responses = this.sysDeptPostMapper.userListByDeptId(request.getDeptId());
//        return responses;
//    }
//
//    @Override
//    public List<DeptUserItemResponse> deptUserList() {
//        return this.userInfosMapper.getDeptUserList();
//    }
//
//    @Override
//    public String uploadHeaderImg(MultipartFile file) {
//        String imgUrl = this.fileService.addImg(file);
//        return imgUrl;
//    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(EditUserRequest request) {
        UserInfo userInfo = this.userInfosMapper.selectOne(new QueryWrapper<UserInfo>()
                .eq("user_id", request.getUserId()));
        UserAccount userAccount = this.userAccountMapper.getOneById(request.getUserId());
        if(!StringUtils.isEmpty(request.getAvatar())){
            userAccount.setAvatar(request.getAvatar());
        }
        BeanUtils.copyProperties(request,userInfo);
        this.userInfosMapper.updateById(userInfo);
        this.userAccountMapper.updateById(userAccount);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String userId) {
        this.userAccountMapper.deleteById(userId);
        this.userInfosMapper.delete(new QueryWrapper<UserInfo>()
                .eq("user_id",userId));
    }

    @Override
    @SneakyThrows
    public List<UserItemResponse> listByMyDeptUser() {
        List<UserItemResponse> result = Lists.newArrayList();
        String userId = UACUserContext.currentUserOrAnonymous().getUserId();
        List<DeptItemVo> deptIdByUid = userInfosMapper.getDeptIdByUid(userId);
        if(deptIdByUid.size()>0){
            List<String> deptIds = deptIdByUid.stream().map(res -> res.getDeptId())
                    .collect(Collectors.toList());
            result = sysDeptPostMapper.userListByDeptIds(deptIds).stream()
                    .filter(one->!one.getId().equals(userId) && !StringUtils.isEmpty(one.getId()))
                    .collect(Collectors.toList());
        }
        else {
            throw Result.failure(ErrCode.DEPT_EXISTS_ERROR).wrap();
        }
        return result;
    }

    private UACTokenInfo buildToken(String sysNodeCode, String userId) {
        UACTokenInfo tokenInfo = jwtUtil.generateToken(sysNodeCode, userId);
        TokenCacheUtils.setAuthCache(tokenInfo.getId(), tokenInfo);
        return tokenInfo;
    }
}
